/* Copyright Statement:
*
* This software/firmware and related documentation ("MediaTek Software") are
* protected under relevant copyright laws. The information contained herein
* is confidential and proprietary to MediaTek Inc. and/or its licensors.
* Without the prior written permission of MediaTek inc. and/or its licensors,
* any reproduction, modification, use or disclosure of MediaTek Software,
* and information contained herein, in whole or in part, shall be strictly prohibited.
*/
/* MediaTek Inc. (C) 2015. All rights reserved.
*
* BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
* THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
* RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
* AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
* NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
* SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
* SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
* THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
* THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
* CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
* SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
* STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
* CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
* AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
* OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
* MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
*/
#include <platform/upmu_hw.h>
#include <debug.h>
#define UINT32P         (volatile unsigned int *)
#define MD_PERI_MISC_BASE				(0x20060000)
#define REG_MD_MDSYS_AP_PMS			(UINT32P (MD_PERI_MISC_BASE+0x0090))
#define REG_MD_PERISYS1_AP_PMS			(UINT32P (MD_PERI_MISC_BASE+0x0094))
#define REG_MD_PERISYS2_AP_PMS			(UINT32P (MD_PERI_MISC_BASE+0x0098))
#define REG_MD_PSMCUAPB_AP_PMS			(UINT32P (MD_PERI_MISC_BASE+0x009C))
#define REG_MD_L1SYS_PMS			(UINT32P (MD_PERI_MISC_BASE+0x00C4))
#define MD_P_TOPSM_BASE				(0x200D0000)
#define REG_MD_P_TOPSM_RM_PWR0_CON		(UINT32P (MD_P_TOPSM_BASE+0x0800))
#define REG_MD_P_TOPSM_RM_PWR1_CON		(UINT32P (MD_P_TOPSM_BASE+0x0804))
#define REG_MD_P_TOPSM_RM_PWR2_CON		(UINT32P (MD_P_TOPSM_BASE+0x0808))
#define REG_MD_P_TOPSM_RM_PWR3_CON		(UINT32P (MD_P_TOPSM_BASE+0x080C))
#define REG_MD_P_TOPSM_RM_PWR4_CON		(UINT32P (MD_P_TOPSM_BASE+0x0810))
#define REG_MD_P_TOPSM_RM_TMR_PWR0		(UINT32P (MD_P_TOPSM_BASE+0x0018))
#define REG_MD_P_TOPSM_RM_TMR_PWR1		(UINT32P (MD_P_TOPSM_BASE+0x001C))
#define MD_L1_TOPSM_BASE			(0x26070000)
#define REG_MD_L1_TOPSM_SM_TMR_PWR0		(UINT32P (MD_L1_TOPSM_BASE+0x0140))
#define REG_MD_L1_TOPSM_SM_TMR_PWR1		(UINT32P (MD_L1_TOPSM_BASE+0x0144))
#define REG_MD_L1_TOPSM_SM_TMR_PWR2		(UINT32P (MD_L1_TOPSM_BASE+0x0148))
#define REG_MD_L1_TOPSM_SM_TMR_PWR3		(UINT32P (MD_L1_TOPSM_BASE+0x014C))
#define REG_MD_L1_TOPSM_SM_TMR_PWR4		(UINT32P (MD_L1_TOPSM_BASE+0x0150))
#define MD_MIXEDSYS_TOPSM_BASE			(0x2616B000)
#define MIXEDSYS_TOPSM_SM_PWR_CON0		(UINT32P (MD_MIXEDSYS_TOPSM_BASE+0x000))
#define MIXEDSYS_TOPSM_SM_PWR_PER0		(UINT32P (MD_MIXEDSYS_TOPSM_BASE+0x0C0))
#define MIXEDSYS_TOPSM_SM_PWR_PER1		(UINT32P (MD_MIXEDSYS_TOPSM_BASE+0x0C4))
#define MIXEDSYS_TOPSM_SM_PWR_SW_CTRL_SEL	(UINT32P (MD_MIXEDSYS_TOPSM_BASE+0x0CC))
#define MIXEDSYS_TOPSM_SM_TMR_REQ_MASK		(UINT32P (MD_MIXEDSYS_TOPSM_BASE+0x100))
#define MIXEDSYS_TOPSM_SM_TMR_SYSCLK_MASK	(UINT32P (MD_MIXEDSYS_TOPSM_BASE+0x108))
#define MIXEDSYS_TOPSM_SM_TMR_PLL_MASK0		(UINT32P (MD_MIXEDSYS_TOPSM_BASE+0x120))
#define MIXEDSYS_TOPSM_SM_TMR_PWR_MASK0		(UINT32P (MD_MIXEDSYS_TOPSM_BASE+0x140))
#define MIXEDSYS_TOPSM_SM_TMR_MAS_TRIG_MASK	(UINT32P (MD_MIXEDSYS_TOPSM_BASE+0x160))
#define MIXEDSYS_TOPSM_SM_TMR_TIMER_TRIG_MASK	(UINT32P (MD_MIXEDSYS_TOPSM_BASE+0x170))
#define MIXEDSYS_TOPSM_SM_TMR_CLIENT_ACT_MASK	(UINT32P (MD_MIXEDSYS_TOPSM_BASE+0x180))
#define MIXEDSYS_TOPSM_SM_SLV_REQ_MASK		(UINT32P (MD_MIXEDSYS_TOPSM_BASE+0x200))
#define MIXEDSYS_TOPSM_SM_SLV_SYSCLK_MASK	(UINT32P (MD_MIXEDSYS_TOPSM_BASE+0x208))
#define MIXEDSYS_TOPSM_SM_SLV_PLL_MASK0		(UINT32P (MD_MIXEDSYS_TOPSM_BASE+0x220))
#define MIXEDSYS_TOPSM_SM_SLV_PWR_MASK0		(UINT32P (MD_MIXEDSYS_TOPSM_BASE+0x240))
#define MIXEDSYS_TOPSM_SM_SLV_MAS_TRIG_MASK	(UINT32P (MD_MIXEDSYS_TOPSM_BASE+0x260))
#define MIXEDSYS_TOPSM_SM_SLV_TIMER_TRIG_MASK	(UINT32P (MD_MIXEDSYS_TOPSM_BASE+0x270))
#define MIXEDSYS_TOPSM_SM_SLV_CLIENT_ACT_MASK	(UINT32P (MD_MIXEDSYS_TOPSM_BASE+0x280))
#define MIXEDSYS_TOPSM_SM_DBG_REQ_MASK		(UINT32P (MD_MIXEDSYS_TOPSM_BASE+0x300))
#define MIXEDSYS_TOPSM_SM_DBG_SYSCLK_MASK	(UINT32P (MD_MIXEDSYS_TOPSM_BASE+0x308))
#define MIXEDSYS_TOPSM_SM_DBG_PLL_MASK0		(UINT32P (MD_MIXEDSYS_TOPSM_BASE+0x320))
#define MIXEDSYS_TOPSM_SM_DBG_PWR_MASK0		(UINT32P (MD_MIXEDSYS_TOPSM_BASE+0x340))
#define MIXEDSYS_TOPSM_SM_DBG_MAS_TRIG_MASK	(UINT32P (MD_MIXEDSYS_TOPSM_BASE+0x360))
#define MIXEDSYS_TOPSM_SM_DBG_TIMER_TRIG_MASK	(UINT32P (MD_MIXEDSYS_TOPSM_BASE+0x370))
#define MIXEDSYS_TOPSM_SM_DBG_CLIENT_ACT_MASK	(UINT32P (MD_MIXEDSYS_TOPSM_BASE+0x380))
#define MIXEDSYS_TOPSM_SM_CLK_SETTLE		(UINT32P (MD_MIXEDSYS_TOPSM_BASE+0x400))
#define MIXEDSYS_TOPSM_SM_TIMER_TRIG_SETTLE	(UINT32P (MD_MIXEDSYS_TOPSM_BASE+0x410))
#define MIXEDSYS_TOPSM_SM_MAS_TRIG_MAX_SETTLE	(UINT32P (MD_MIXEDSYS_TOPSM_BASE+0x418))
#define MIXEDSYS_TOPSM_SM_MAS_TRIG_GRP_SETTLE	(UINT32P (MD_MIXEDSYS_TOPSM_BASE+0x420))
#define MIXEDSYS_TOPSM_SM_MAS_TRIG_GRP_SAL	(UINT32P (MD_MIXEDSYS_TOPSM_BASE+0x430))
#define MIXEDSYS_TOPSM_SM_MAS_TRIG_SEL		(UINT32P (MD_MIXEDSYS_TOPSM_BASE+0x440))
#define MIXEDSYS_TOPSM_SM_SLV_SW_TRIG		(UINT32P (MD_MIXEDSYS_TOPSM_BASE+0x450))
#define MIXEDSYS_TOPSM_SM_DBG_SW_TRIG		(UINT32P (MD_MIXEDSYS_TOPSM_BASE+0x458))
#define STA_POWER_DOWN  0
#define STA_POWER_ON    1
static void internal_md1_power_down(void)
{
	int ret = 0;
	/* 0. power on md */
	ret = spm_mtcmos_ctrl_md1(STA_POWER_ON);
	dprintf(CRITICAL, "[ccci-off]0.power on MD_INFRA/MODEM_TOP ret=%d\n", ret);
	if (ret)
		return;
	/* 1. pms init */
	dprintf(CRITICAL, "[ccci-off]pms init\n");
	*REG_MD_MDSYS_AP_PMS = 0x0000FFFF;
	*REG_MD_PERISYS1_AP_PMS = 0x0000FFFF;
	*REG_MD_PERISYS2_AP_PMS = 0x0000FFFF;
	*REG_MD_PSMCUAPB_AP_PMS = 0x0000FFFF;
	*REG_MD_L1SYS_PMS = 0x00000007;
	/* 2. mixedsys topsm init, for release srcclkena in kernel */
	dprintf(CRITICAL, "[ccci-off]mixedsys topsm init\n");
	*MIXEDSYS_TOPSM_SM_PWR_PER0 = 0x3252511D;
	*MIXEDSYS_TOPSM_SM_PWR_PER1 = 0x05003337;
	*MIXEDSYS_TOPSM_SM_PWR_SW_CTRL_SEL = 0x0;
	*MIXEDSYS_TOPSM_SM_TMR_REQ_MASK = 0x1;
	*MIXEDSYS_TOPSM_SM_TMR_SYSCLK_MASK = 0x01010101;
	*MIXEDSYS_TOPSM_SM_TMR_PLL_MASK0 = 0x1;
	*MIXEDSYS_TOPSM_SM_TMR_PWR_MASK0 = 0x1;
	*MIXEDSYS_TOPSM_SM_TMR_MAS_TRIG_MASK = 0x1;
	*MIXEDSYS_TOPSM_SM_TMR_TIMER_TRIG_MASK = 0x1;
	*MIXEDSYS_TOPSM_SM_TMR_CLIENT_ACT_MASK = 0x1;
	*MIXEDSYS_TOPSM_SM_SLV_REQ_MASK = 0x0;
	*MIXEDSYS_TOPSM_SM_SLV_SYSCLK_MASK = 0x03030300;
	*MIXEDSYS_TOPSM_SM_SLV_PLL_MASK0 = 0x3;
	*MIXEDSYS_TOPSM_SM_SLV_PWR_MASK0 = 0x0;
	*MIXEDSYS_TOPSM_SM_SLV_MAS_TRIG_MASK = 0x3;
	*MIXEDSYS_TOPSM_SM_SLV_TIMER_TRIG_MASK = 0x3;
	*MIXEDSYS_TOPSM_SM_SLV_CLIENT_ACT_MASK = 0x3;
	*MIXEDSYS_TOPSM_SM_DBG_REQ_MASK = 0x1;
	*MIXEDSYS_TOPSM_SM_DBG_SYSCLK_MASK = 0x01010101;
	*MIXEDSYS_TOPSM_SM_DBG_PLL_MASK0 = 0x1;
	*MIXEDSYS_TOPSM_SM_DBG_PWR_MASK0 = 0x1;
	*MIXEDSYS_TOPSM_SM_DBG_MAS_TRIG_MASK = 0x1;
	*MIXEDSYS_TOPSM_SM_DBG_TIMER_TRIG_MASK = 0x1;
	*MIXEDSYS_TOPSM_SM_DBG_CLIENT_ACT_MASK = 0x1;
	*MIXEDSYS_TOPSM_SM_PWR_CON0 = 0xB2002501;
	*MIXEDSYS_TOPSM_SM_CLK_SETTLE = 0x50086;
	*MIXEDSYS_TOPSM_SM_TIMER_TRIG_SETTLE = 0x4;
	*MIXEDSYS_TOPSM_SM_MAS_TRIG_MAX_SETTLE = 0x14;
	*MIXEDSYS_TOPSM_SM_MAS_TRIG_GRP_SETTLE = 0x14;
	*MIXEDSYS_TOPSM_SM_MAS_TRIG_GRP_SAL = 0x8;
	*MIXEDSYS_TOPSM_SM_MAS_TRIG_SEL = 0x0;
	*MIXEDSYS_TOPSM_SM_SLV_SW_TRIG = 0x00000000;
	*MIXEDSYS_TOPSM_SM_DBG_SW_TRIG = 0x00000000;
	/* 3. Shutting off ARM7, HSPAL2, LTEL2 power domains */
	/* Shutting off ARM7 through software */
	*REG_MD_P_TOPSM_RM_PWR1_CON &= ~0xE6045;
	*REG_MD_P_TOPSM_RM_PWR1_CON |= 0xB8;
	/* Masking control of ostimer on ARM7,HSPAL2,LTEL2 */
	*REG_MD_P_TOPSM_RM_TMR_PWR0 = 0x01;
	/* De-asserting software power req */
	*REG_MD_P_TOPSM_RM_PWR0_CON &= ~0x44; /* PSMCU */
	*REG_MD_P_TOPSM_RM_PWR2_CON &= ~0x44; /* LTEL2 */
	*REG_MD_P_TOPSM_RM_PWR3_CON &= ~0x44; /* LTEL2 */
	*REG_MD_P_TOPSM_RM_PWR4_CON &= ~0x44; /* INFRA */
	/* 4. PSMCU and INFRA power domains should be shut off at the end,
	after complete register sequence has been executed: */
	*REG_MD_P_TOPSM_RM_TMR_PWR0 = 0x00; /* PSMCU into sleep */
	*REG_MD_P_TOPSM_RM_TMR_PWR1 = 0x00; /* INFRA into sleep */
	/* 5. Shutting off power domains except L1MCU by masking all ostimers control
	on mtcmos power domain: */
	*REG_MD_L1_TOPSM_SM_TMR_PWR0 |= ~(0x1);
	*REG_MD_L1_TOPSM_SM_TMR_PWR1 = 0xFFFFFFFF;
	*REG_MD_L1_TOPSM_SM_TMR_PWR2 = 0xFFFFFFFF;
	*REG_MD_L1_TOPSM_SM_TMR_PWR3 = 0xFFFFFFFF;
	*REG_MD_L1_TOPSM_SM_TMR_PWR4 = 0xFFFFFFFF;
	/* 6. L1MCU power domain is shut off in the end
	after all register sequence has been executed: */
	*REG_MD_L1_TOPSM_SM_TMR_PWR0 = 0xFFFFFFFF;
	dprintf(CRITICAL, "[ccci-off]8.power off ARM7, HSPAL2, LTEL2\n");
	/* no need to poll, as MD SW didn't run and enter sleep mode, polling will not get result */
	spm_mtcmos_ctrl_md1(STA_POWER_DOWN);

	/* vpmic no need power off*/
	dprintf(CRITICAL, "[ccci-off]9.For option 1, no power off md1 pmic\n");
}

void md1_power_down(void)
{
	unsigned int val;

	val = get_devinfo_with_index(4);
	if ((val & (0x1 << 3)) == 0)
		internal_md1_power_down();
	else
		dprintf(CRITICAL, "[ccci-off]md1 effused,no need power off\n");
}
